package com.janetfilter.core.commons;

import com.janetfilter.core.models.FilterRule;
import com.janetfilter.core.utils.StringUtils;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 配置解析器类，负责解析配置文件
 * 配置文件格式为INI格式，支持节（section）和规则（rule）
 * 
 * 配置文件示例：
 * [Section1]
 * EQUAL,value1
 * REGEXP,value.*
 * 
 * [Section2]
 * PREFIX,value2
 */
public class ConfigParser {
    /**
     * 解析配置文件
     * 
     * @param file 配置文件对象
     * @return 解析后的配置，key为节名，value为该节包含的规则列表
     * @throws Exception 如果解析过程中发生错误
     */
    public static Map<String, List<FilterRule>> parse(File file) throws Exception {
        // 创建结果映射
        Map<String, List<FilterRule>> map = new HashMap<>();

        // 检查文件是否可读
        if (null == file || !file.exists() || !file.isFile() || !file.canRead()) {
            return map;
        }

        // 使用try-with-resources确保文件正确关闭
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8))) {
            int lineNumber = 0;
            String line, lastSection = null;

            // 逐行读取文件
            while (null != (line = reader.readLine())) {
                lineNumber++;
                line = line.trim();
                if (StringUtils.isEmpty(line)) {
                    continue;  // 跳过空行
                }

                int len = line.length();
                switch (line.charAt(0)) {
                    case '[':  // 节定义，如[SectionName]
                        if (']' != line.charAt(len - 1)) {
                            throw new Exception("Invalid section! Line: " + lineNumber);
                        }

                        // 提取节名
                        String section = line.substring(1, len - 1);
                        if (StringUtils.isEmpty(section)) {
                            throw new Exception("Empty section name! Line: " + lineNumber);
                        }

                        // 将节名添加到映射，并设置为当前节
                        map.computeIfAbsent(lastSection = section, k -> new ArrayList<>());
                        break;
                    case '#':  // 注释
                    case ';':  // 注释
                        break;
                    case '/':  // 可能是注释 //
                        if (len > 1 && '/' == line.charAt(1)) {
                            break;  // 注释 //
                        }
                        throw new Exception("Invalid character! Line: " + lineNumber);
                    default:  // 规则定义
                        if (null == lastSection) {
                            break;  // 忽略没有节的规则
                        }

                        // 解析规则，格式为：类型,内容
                        String[] parts = line.split(",", 2);
                        if (2 != parts.length) {
                            throw new Exception("Invalid rule! Line: " + lineNumber);
                        }

                        String type = parts[0].trim();
                        String content = parts[1].trim();
                        if (StringUtils.isEmpty(type) || StringUtils.isEmpty(content)) {
                            throw new Exception("Invalid rule! Line: " + lineNumber);
                        }

                        // 类型第一个字符必须是字母
                        if (!Character.isAlphabetic(type.charAt(0))) {
                            throw new Exception("Invalid rule! Line: " + lineNumber);
                        }

                        // 创建过滤规则
                        FilterRule rule = FilterRule.of(type, content);
                        if (null == rule) {
                            throw new Exception("Invalid rule type! Line: " + lineNumber);
                        }

                        // 将规则添加到当前节
                        map.get(lastSection).add(rule);
                        DebugInfo.debug("Add section: " + lastSection + ", rule: " + rule);
                        break;
                }
            }
        }

        DebugInfo.debug("Config file loaded: " + file);
        return map;
    }
}
